package cn.itsource.ymcc.service.impl;

import cn.itsource.exception.GlobalException;
import cn.itsource.util.AssertUtil;
import cn.itsource.ymcc.domain.PayFlow;
import cn.itsource.ymcc.domain.PayOrder;
import cn.itsource.ymcc.dto.AlipayNotifyDto;

import cn.itsource.ymcc.dto.PayAliNotifyDto;
import cn.itsource.ymcc.service.IPayFlowService;
import cn.itsource.ymcc.service.IPayNotifyService;
import cn.itsource.ymcc.service.IPayOrderService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.easysdk.factory.Factory;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class PayNotifyServiceImpl implements IPayNotifyService {
    @Autowired
    private IPayOrderService payOrderService;
    @Autowired
    private IPayFlowService payFlowService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 支付宝支付回调
     *  1.判断交易状态，来决定我们的业务是否需要处理
     *  2.验证签名  支付宝给我们提供了一个验证签名的接口
     *  3.业务校验，订单是不是我们的 钱钱对不对
     *  4.判断我们的支付单的状态是否满足条件
     *
     *  5.修改支付单状态
     *  6.记录交易流水
     *
     *  7.发送处理支付结果的事务消息
     *    7.1 订单服务 广播消费消息 处理订单
     *    7.2 课程服务 广播消费消息  添加购买记录
     * @param dto
     */
    @Override
    public String notify(AlipayNotifyDto dto) {
        log.info("支付宝异步通知");
        // 1.判断交易状态
        AssertUtil.isTrue(dto.isTradeSuccess(),"交易失败！");
        Map map = JSONObject.parseObject(JSON.toJSONString(dto), Map.class);
        try {
            // 2.验证签名
            Boolean isVerify = Factory.Payment.Common().verifyNotify(map);
            if(!isVerify){
                return "SUCCESS";// 验签失败，停止调用
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "ERROR";
        }
        // 3.业务校验，订单是不是我们的 钱钱对不对
        PayOrder payOrder = payOrderService.checkPayOrder(dto.getOut_trade_no());
        if(payOrder == null){
            return "SUCCESS";//订单不存在
        }
        int amountEq = new BigDecimal(dto.getTotal_amount()).compareTo(payOrder.getAmount());
        if(amountEq != 0){
            return "SUCCESS";//金额不正确，停止调用
        }
        // 4.判断我们的支付单的状态是否满足条件
        boolean isWaitPay = payOrder.getPayStatus() == PayOrder.STATE_WAIT_PAY;
        if(!isWaitPay){
            //@ 退款逻辑
            try {
                log.info("主动退款。。。。");
                Factory.Payment.Common().refund(payOrder.getOrderNo(),payOrder.getAmount().toString());
            } catch (Exception e) {
                e.printStackTrace();
                //走人工介入
            }
            return "SUCCESS";//支付单状态不对，不在通知
        }

        // 修改订单信息
        payOrder.setPayStatus(PayOrder.STATE_SUCCESS);
        Date now = new Date();
        payOrder.setUpdateTime(now);

        // 记录交易流水单
        PayFlow flow = new PayFlow();
        flow.setNotifyTime(now);
        flow.setSubject(payOrder.getSubject());
        flow.setOutTradeNo(dto.getOut_trade_no());
        flow.setTotalAmount(new BigDecimal(dto.getTotal_amount()));
        flow.setTradeStatus(dto.getTrade_status());
        flow.setCode(dto.getCode());
        flow.setMsg(dto.getMsg());
        flow.setPassbackParams(dto.getPassback_params());
        flow.setPaySuccess(dto.isTradeSuccess());

        Map<String, Object> transMap = new HashMap<>();
        transMap.put("payOrder",payOrder);
        transMap.put("flow",flow);
        // 7.发送处理支付结果的事务消息
        //   7.1 订单服务 广播消费消息 处理订单
        //   7.2 课程服务 广播消费消息  添加购买记录
        //  订单号  购买人ID  课程ID
        PayAliNotifyDto payAliNotifyDto = new PayAliNotifyDto(
                payOrder.getOrderNo(),
                payOrder.getExtParams()
        );
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(payAliNotifyDto)).build();
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                "TxPayAliNotifyGroup",//同监听器组名
                "paynofity-topic:aliay-tags",
                message,//p
                transMap// 本地事务要执行的内容
        );

        //执行本地事务的状态
        log.info("发送事务消息开始");
        LocalTransactionState localTransactionState = sendResult.getLocalTransactionState();
        //发送消息状态
        SendStatus sendStatus = sendResult.getSendStatus();
        log.info("发送事务消息完成");

        if( localTransactionState != LocalTransactionState.COMMIT_MESSAGE || sendStatus != SendStatus.SEND_OK ){
            throw new GlobalException("处理支付结果失败！","401");
        }

        return "SUCCESS";
    }

    @Override
    public void updatePayOrderAndInsertFlow(Map<String, Object> map) {
        PayOrder payOrder = (PayOrder) map.get("payOrder");
        PayFlow flow = (PayFlow) map.get("flow");
        PayOrder payOrderTmp = payOrderService.selectById(payOrder.getId());
        boolean isWaitePay = payOrderTmp.getPayStatus() == PayOrder.STATE_WAIT_PAY;
        AssertUtil.isTrue(isWaitePay,"信息异常！");
        payOrderService.updateById(payOrder);
        payFlowService.insert(flow);
    }

}
